/*
 * @Author: lp
 * @Date: 2022-01-18 14:46:09
 * @LastEditTime: 2022-06-22 09:50:42
 * @LastEditors: lp 654528967@qq.com
 * @Description: 常用公共方法
 * @FilePath: //nien-vue3-admin//src//utils//index.ts
 */
import type { ElForm } from 'element-plus'
import { ElMessage } from 'element-plus'
import { computed, ref } from 'vue' 
// import { relative } from 'path-browserify'
import router from '@/router'
import request from './request'
import useDict, { DictDirection } from '@/store/modules/dicts'
/**
 * @description: 列表合计
 * @param {Array<{column: string, valueFormatter:Function }>} sumColums:需要合计的列，不传展示所有
 * @param {string} label
 * @return {*} function
 */

export const getSummaries = (sumColums:Array<{column:string, valueFormatter?: (sum) => any}>, label = '合计') => (params) => {
  const { columns, data } = params
  const sums: string[] = []
  columns.forEach((column, index) => {
    if (index === 0) {
      sums[index] = label
      return
    }
    const curColumn = sumColums.find(i => i.column === column.property)
    if (Array.isArray(sumColums) && !curColumn) {
      sums[index] = ''
      return
    }
    const values = data.map((item) => Number(item[column.property]))
    const sum = values.reduce((prev, curr) => {
      if (!Number.isNaN(curr)) {
        return prev + curr
      } 
      return prev
    }, 0)
    sums[index] = curColumn.valueFormatter ? curColumn.valueFormatter(sum) : sum
  })
  return sums
}
/**
 * @description: 验证是否外链
 * @param {string} path
 * @return {*} boolean
 */
export const isExternal = (path: string) => /^(https?:|mailto:|tel:)/.test(path)
/**
 * @description: 树形结构数据处理
 * @param {*} data
 * @param {*} id
 * @param {*} parentId
 * @param {*} rootId
 * @return {*}
 */
export function handleTree(data, id = 'id', parentId = 'parentId', rootId = 0) {
  const cloneData = JSON.parse(JSON.stringify(data))
  const treeData = cloneData.filter((father) => {
    const branchArr = cloneData.filter((child) => father[id] == child[parentId])
    branchArr.length > 0 && (father.children = branchArr)
    return father[parentId] == rootId
  })
  return treeData != '' ? treeData : data
}
/**
 * @description: 表单重置
 * @param {InstanceType} form 表单虚拟dom，setup应为xx.value
 * @return {*}
 */
export const resetForm = (form: InstanceType<typeof ElForm> | undefined) => {
  if (!form) return
  form.resetFields()
}
/**
 * @description: 表单验证
 * @param {InstanceType} form
 * @param {function} callback
 * @return {*}
 */
export const validateForm = (formEl: InstanceType<typeof ElForm> | undefined, callback: (value?:unknown) => void) => {
  if (!formEl) return
  formEl.validate((valid) => {
    if (valid) {
      callback()
    } else {
      ElMessage.error('必填项未输入')
      return false
    }
  })
}
/**
 * @description: 克隆对象
 * @param {object} 原对象
 * @return {*} 克隆后的对象
 */
export const depClone = (obj) => {
  let temp = null
  if (obj instanceof Array) {
    temp = obj.concat()
  } else if (obj instanceof Function) {
    // 函数是共享的是无所谓的，js也没有什么办法可以在定义后再修改函数内容
    temp = obj
  } else {
    temp = {}
    for (const item in obj) {
      const val = obj[item]
      temp[item] = Object.prototype.toString.call(val) === '[object Object]' ? depClone(val) : val // 这里也没有判断是否为函数，因为对于函数，我们将它和一般值一样处理
    }
  }
  return temp
}
/**
 * @description:
 * @param {params} 原参数
 * @param {dateRange} 日期对象
 * @return {object} 包含日期参数 beginTime endTime
 */
export const addDateRange = (params: Record<string, any>, dateRange: string[]) => {
  const search = depClone(params)
  search.beginTime = ''
  search.endTime = ''
  if (Array.isArray(dateRange) && dateRange.length == 2) {
    search.beginTime = dateRange[0]
    search.endTime = dateRange[1]
  }
  return search
}
/**
 * @description: 字典回选
 * @param {datas} 插槽作用域行数据
 * @param {value} 回选的键名
 * @param {dictLabel} 显示值的键名
 * @param {dictValue} 真实值的键名
 * @return {string} 回选的值
 */
export const selectDictLabel = (datas: object[], value: string | number, dictLabel = 'dictLabel', dictValue = 'dictValue'): string => {
  const actions = []
  Object.keys(datas).some((key) => {
    if (datas[key][dictValue] == `${ value }`) {
      actions.push(datas[key][dictLabel])
      return true
    }
    return false
  })
  return actions.join('')
}
// 格式化空字符
export function praseStrEmpty(str: string) {
  if (!str || str == 'undefined' || str == 'null') return ''
  return str
}

export function getDict(url: string) {
  return request({ url: '/system/dict/data/query', method: 'post', data: { dictType: url, pageNum: 0, pageSize: 0 } })
}
// 参数格式化，用于多个订单号，运单号等搜索框
export function replaceParams(val) {
  // eslint-disable-next-line no-useless-escape
  const regx = /[\s|\||\r]/g
  let orderNo = val || ''
  orderNo = orderNo.replace(/[\r|\n|\r\n|,|,]/g, ' ')
  orderNo = orderNo.trim()
  orderNo.replace(/\s/g, '')
  orderNo = orderNo.split(regx)
  let newNo:any = []
  orderNo = orderNo.forEach(el => {
    if (el) {
      newNo.push(el)
    }
  })
  newNo = newNo.join(',')
  return newNo
}
// 时间格式化
export function parseTime(time: object | string | number, pattern = '{y}-{m}-{d} {h}:{i}:{s}') {
  if (arguments.length === 0 || !time) {
    return null
  }
  let date
  if (typeof time === 'object') {
    date = time
  } else {
    if (typeof time === 'string' && /^[0-9]+$/.test(time)) {
      time = parseInt(time)
    } else if (typeof time === 'string') {
      time = time.replace(new RegExp(/-/gm), '/')
    }
    if (typeof time === 'number' && time.toString().length === 10) {
      time *= 1000
    }
    date = new Date(time)
  }
  const formatObj = {
    y: date.getFullYear(),
    m: date.getMonth() + 1,
    d: date.getDate(),
    h: date.getHours(),
    i: date.getMinutes(),
    s: date.getSeconds(),
    a: date.getDay(),
  }
  const timeStr = pattern.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
    let value = formatObj[key]
    // Note: getDay() returns 0 on Sunday
    if (key === 'a') {
      return ['日', '一', '二', '三', '四', '五', '六'][value]
    }
    if (result.length > 0 && value < 10) {
      value = `0${ value }`
    }
    return value || 0
  })
  return timeStr
}
declare global {
    interface Navigator {
        msSaveBlob?: (blob: any, defaultName?: string) => boolean
    }
}
export function tableSum(param, filterList = [], rows = []) {
  try {
    const { columns = [], data: oldData } = param
    const data = rows.length == 0 ? oldData : rows
    const sums = []
    columns.forEach((column, index) => {
      if (index === 0) {
        sums[index] = '合计'
        return
      } if (filterList.some(el => el == column.property)) {
        sums[index] = ''
        return
      }
      const values = data.map(item => {
        if (column.property && column.property.includes('[')) {
          const strArr = column.property.split('[')
          return Number(item[strArr[0]][strArr[1].slice(0, -1)])
        } 
        return Number(item[column.property])
      })
      if (!values.every(value => Number.isNaN(value))) {
        sums[index] = values
        .reduce((prev, curr) => {
          const value = Number(curr)
          if (!Number.isNaN(value)) {
            return prev + curr
          } 
          return prev
        }, 0)
        .toFixed(2)
        sums[index] += ''
      } else {
        sums[index] = ''
      }
    })
    return [sums]
  } catch (error) {
    console.log(error)
  }
}
// 下载
export function download(url: string, params: { [key: string]: any }, filename: string) {
  return request
  .post(url, params, {
    responseType: 'blob',
  })
  .then((data) => {
    const content = data
    const blob = new Blob([content])
    if ('download' in document.createElement('a')) {
      const elink = document.createElement('a')
      elink.download = filename
      elink.style.display = 'none'
      elink.href = URL.createObjectURL(blob)
      document.body.appendChild(elink)
      elink.click()
      URL.revokeObjectURL(elink.href)
      document.body.removeChild(elink)
    } else {
      window.navigator.msSaveBlob(blob, filename)
    }
  })
  .catch((r) => {
    console.error(r)
  })
}
// 重写的下载方法
export function download2(url: string, params: { [key: string]: any }, filename: string) {
  return request
  .post(url, params, {
    responseType: 'blob',
  })
  .then(data => {
    const content = data
    const blob = new Blob([content])
    if ('download' in document.createElement('a')) {
      const elink = document.createElement('a')
      elink.download = filename
      elink.style.display = 'none'
      elink.href = URL.createObjectURL(blob)
      document.body.appendChild(elink)
      elink.click()
      URL.revokeObjectURL(elink.href)
      document.body.removeChild(elink)
    } else {
      navigator.msSaveBlob(blob, filename)
    }
  })
  .catch(r => {
    console.error(r)
  })
}
/**
 * @description: 字符串转驼峰支持 _ -
 * @param {*} str 字符串
 * @return {*}  驼峰字符串
 */
export function toHumpName(str: string): string {
  const re = /(-|_)(\w)/g // \w匹配所有的字母和数字字符以及下划线_
  // 第一个参数re表示正则,第二个回调函数,对该字符串处理方式,圆括号内的形参数表示正则表达式的子选项
  return str.replace(re, ($0, $1, $2) => $2.toUpperCase())
}
// 文件转图片；
interface HTMLImageElement {
 onerror?: (this: any, ev: Event) => any
 onload?: (this: any, ev: Event) => any
 src?:string|ArrayBuffer,
 width?:number,
 height?:number
}
export function readerImg(file) {
  return new Promise((resolve, reject) => {
    const img:HTMLImageElement = new Image()
    const reader = new FileReader()
    reader.readAsDataURL(file)
    reader.onload = (e:{
      target:{
        result:string|ArrayBuffer,
      }
    }) => {
      img.src = e.target.result
    }
    reader.onerror = e => {
      reject(e)
    }
    img.onload = () => {
      resolve(img)
    }
    img.onerror = e => {
      reject(e)
    }
  })
}
// 图片压缩
export async function compressImg({ maxH, maxW, file }:{maxH?:number, maxW?:number, file:File}) {
  const loadImg:any = await readerImg(file)
  const type = file.type
  return new Promise((resolve) => {
    const { width: originWidth, height: originHeight } = loadImg
    const maxWidth = maxW || 1000,
      maxHeight = maxH || 1000
    let targetWidth = originWidth,
      targetHeight = originHeight
    if (originWidth > maxWidth || originHeight > maxHeight) {
      if (originWidth / originHeight > 1) {
        // 宽图片；
        targetWidth = maxWidth
        targetHeight = Math.round(maxWidth * (originHeight / originWidth))
      } else {
        // 高图片
        targetHeight = maxHeight
        targetWidth = Math.round(maxHeight * (originWidth / originHeight))
      }
    }
    const canvas = document.createElement('canvas')
    const context = canvas.getContext('2d')
    canvas.width = targetWidth
    canvas.height = targetHeight
    context.clearRect(0, 0, targetWidth, targetHeight)
    context.drawImage(loadImg, 0, 0, targetWidth, targetHeight)
    canvas.toBlob(f => {
      // blob转文件对象;
      const files = new window.File([f], file.name, { type })
      resolve(files)
    }, type || 'image/png')
  })
}
  
// 图片压缩 参数为 文件列表和需要append的表单对象
export function zipImg({ fileList, formData, key = 'file' }) {
  return new Promise(resolve => {
    if (fileList.length > 0) {
      fileList.forEach(async (el, index) => {
        const img = await compressImg({ file: el.raw })
        formData.append(key, img)
        if (index == fileList.length - 1) {
          resolve(true)
        }
      })
    } else {
      resolve(false)
    }
  })
}
// 区分测试环境
export function isTest() {
  const host = window.location.host,
    localList = ['106.14.173.99', 'testym', 'localhost', '127.0.0.1']
  // 通过端口号，或者域名判断是否正式环境
  return localList.some(el => host.includes(el))
}

export function pxToRem(px) {
  // 设计图1440px的尺寸
  const rootValue = 144
  if (px.includes('px')) {
    px = `${ (Number(px.replace('px', '')) / rootValue).toFixed(4) }rem`
  } else if (!Number.isNaN(px)) {
    px = `${ (px / rootValue).toFixed(4) }rem`
  } else if (px.includes('rem')) {
    return px
  } else {
    console.warn('pxToRem函数请传入px像素或者数字')
    return
  }	
  return px
}

export function mapDicts(arg:string|[string]|Record<DictDirection, any>) {
  const dict = useDict()
  const obj = ref({})
  if (typeof arg === 'string') {
    obj[arg] = () => dict.getDictOption(arg)
  } else if (Array.isArray(arg)) {
    arg.forEach(key => {
      obj[DictDirection[key]] = () => dict.getDictOption(key)
    })
  } else {
    Object.keys(arg).forEach(key => {
      obj[key] = () => dict.getDictOption(arg[key])
    })
  }
  return obj
}

export function useDicts(arg:string|[string|number]|Record<string, any>) {
  const dict = useDict()
  const obj:Record<string|number, any> = ref({})
  if (typeof arg === 'string') {
    dict.getDictOption(arg)
    obj[arg] = computed(() => dict[arg])
  } else if (Array.isArray(arg)) {
    arg.forEach(key => {
      dict.getDictOption(key)
      obj[key] = computed(() => dict[key]) 
    })
  } else {
    Object.keys(arg).forEach(key => {
      dict.getDictOption(arg[key])
      obj[key] = computed(() => dict[arg[key]]) 
    })
  }
  return obj
}
// 合计
export function eTableSum(param, filterList = [], rows = [], multiplication) {
  try {
    const { columns = [], data: oldData } = param
    const data = rows.length == 0 ? oldData : rows
    const sums = []
    columns.forEach((column, index) => {
      if (index === 0) {
        sums[index] = '合计'
        return
      } if (filterList.some(el => el == column.property)) {
        sums[index] = ''
        return
      }
      let values = []
      if (multiplication) {
        if (column.property === multiplication) {
          values = data.map(item => Number(item[column.property]))
        } else {
          values = data.map(item => item[column.property] * item[multiplication])
        }
      } else {
        values = data.map(item => Number(item[column.property]))
      }
      if (!values.every(value => Number.isNaN(value))) {
        sums[index] = values
        .reduce((prev, curr) => {
          const value = Number(curr)
          if (!Number.isNaN(value)) {
            return prev + curr
          } 
          return prev
        }, 0)
        .toFixed(2)
        sums[index] += ''
      } else {
        sums[index] = ''
      }
    })
    return sums
  } catch (error) {
    console.log(error)
  }
}
// 非空判断
export function isEmpty() {
  // eslint-disable-next-line prefer-rest-params
  const list = Array.from(arguments)
  const res = list.every(el => el === undefined || el === null || el === '')
  return res
}
export function uuid() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
    const r = (Math.random() * 16) | 0,
      v = c == 'x' ? r : (r & 0x3) | 0x8
    return v.toString(16)
  })
}
export function queryRedirect() {
  const route = router.currentRoute.value
  return computed(():string => {
    const redirect = route.query.redirect
    if (Array.isArray(redirect)) {
      return redirect.join('/')
    } 
    return redirect
  })
}